// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#ifndef NEBULA_COUNTING_SEMAPHORE_H
#define NEBULA_COUNTING_SEMAPHORE_H

#include <memory>

#include <turbo/utility/status.h>

namespace nebula {
namespace util {

/// \brief Simple mutex-based counting semaphore with timeout
class TURBO_EXPORT CountingSemaphore {
 public:
  /// \brief create an instance with initial_avail starting permits
  ///
  /// \param[in] initial_avail The semaphore will start with this many permits available
  /// \param[in] timeout_seconds A timeout to be applied to all operations.  Operations
  ///            will return turbo::invalid_argument_error if this timeout elapses
  explicit CountingSemaphore(uint32_t initial_avail = 0, double timeout_seconds = 10);
  ~CountingSemaphore();
  /// \brief Block until num_permits permits are available
  turbo::Status Acquire(uint32_t num_permits);
  /// \brief Make num_permits permits available
  turbo::Status Release(uint32_t num_permits);
  /// \brief Wait until num_waiters are waiting on permits
  ///
  /// This method is non-standard but useful in unit tests to ensure sequencing
  turbo::Status WaitForWaiters(uint32_t num_waiters);
  /// \brief Immediately time out any waiters
  ///
  /// This method will return StatusBuilder::OK only if there were no waiters to time out.
  /// Once closed any operation on this instance will return an invalid status.
  turbo::Status close();

 private:
  class Impl;
  std::unique_ptr<Impl> impl_;
};

}  // namespace util
}  // namespace nebula

#endif  // NEBULA_COUNTING_SEMAPHORE_H
